package com.orange.framework.consumer;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;

import com.orange.common.base.entity.ConsumerDto;
import com.orange.common.base.entity.RequestData;
import com.orange.common.base.entity.ResponseData;
import com.orange.framework.consumer.annotation.ConsumerClient;
import com.orange.framework.consumer.annotation.HttpMapping;
import com.orange.framework.consumer.convert.NullConverter;
import com.orange.framework.consumer.convert.ConsumerConverter;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeoutException;

@Slf4j
public class ConsumerHandler extends ProxyInvocationHandler {

    @Override
    protected ResponseData<?> handler(Method method, RequestData<?> arg){
        return this.handler(method, arg,true);
    }

    /**
     * 1、注解判断
     * 2、请求类型转换
     * 3、数据上送
     * 4、请求结果转换
     * 6、异常处理
     * 7、日志打印
     * 8、返回数据封装
     *
     * @Author YWF
     * @Date  2023/2/6 9:19
     * @Param [method, requestData, adapt]
     **/
    protected ResponseData<?> handler(Method method, RequestData<?> requestData, boolean adapt){

        ResponseData<Object> responseData = new ResponseData();
        String transCode = null;
        Object serverBody = null;
        Object resBody = null;
        ConsumerDto communicate = new ConsumerDto();
        Exception exception = null;
        try {
            ConsumerClient annotation = method.getAnnotation(ConsumerClient.class);
            //代理的类
            Class<?> declaringClass = method.getDeclaringClass();
            log.info("代理的类：{}",declaringClass);
            ConsumerClient client = declaringClass.getAnnotation(ConsumerClient.class);
            if (client == null){
                throw new NullPointerException("无法完成请求，请检查方法上是否有ProxyClient注解");
            }
            Class<? extends Consumer> consumerInClass = client.consumerClass();
            if (annotation!=null){
                consumerInClass = annotation.consumerClass();
            }

            HttpMapping mapping = method.getAnnotation(HttpMapping.class);
            if (mapping == null){
                throw new NullPointerException("无法完成请求，请检查方法上是否有ProxyMapping注解");
            }
            // 交易码
            transCode = mapping.transCode();

            Class<? extends ConsumerConverter> convert = mapping.convert();
            ConsumerConverter converter = SpringUtil.getBean(convert);
            Class returnType;
            if (converter == null){
                log.error("容器中没有找到convert实现类");
                converter = new NullConverter();
                returnType = this.getMethodReturnType(method);
            }else{
                Type[] actualTypeArguments = ((ParameterizedType) convert.getGenericInterfaces()[0]).getActualTypeArguments();
                returnType = (Class) actualTypeArguments[2];
            }

            serverBody = converter.convertReq(requestData.getBody(), requestData.getHeader());

            Consumer httpConsumer = SpringUtil.getBean(consumerInClass);
            communicate = httpConsumer.communicate(mapping, serverBody,requestData,returnType);
            Object commBody = communicate.getBody();
            resBody = converter.convertRes(commBody, requestData.getBody());

            log.info("查询结果：{}",communicate);
            responseData.setBody(resBody);
            responseData.setHeader(communicate.getHeader());
            responseData.setStatus(communicate.getStatus());
        }catch (TimeoutException e){
            exception = e;
            log.error("服务超时:", e);
        }catch (Exception e){
            exception = e;
            log.error("程序框架错误:", e);
        }finally {
            this.linkLog(transCode, requestData,communicate,responseData,exception);
        }
        return responseData;
    }

    private Class<?> getMethodReturnType(Method method) {
        ParameterizedType genericReturnType = (ParameterizedType) method.getGenericReturnType();
        Type[] actualTypeArguments = genericReturnType.getActualTypeArguments();
        Class<?> clazz = (Class) actualTypeArguments[0];
        return clazz;
    }

    private void linkLog(String transCode, RequestData<?> requestData, ConsumerDto communicate, ResponseData<Object> responseData, Exception exception) {
        log.info("消费者:系统标准入参->P1: [{}] [{}]", transCode, JSONUtil.toJsonStr(requestData));
        log.info("消费者:对接系统入参->P2: [{}] [{}]", transCode, JSONUtil.toJsonStr(communicate.getServerReq()));
        log.info("消费者:对接系统输出->R3: [{}] [{}]", transCode, JSONUtil.toJsonStr(communicate.getServerRes()));
        log.info("消费者:系统标准输出->R4: [{}] [{}]", transCode, JSONUtil.toJsonStr(responseData));
    }
}
